#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "dirent.h"
#include <sys/types.h>

#define MAX_PATH 260
#define MAX_CODE 512
#define MAX_CONTENT (1024*12)
const char *default_code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static int file_is_h_c(char *file)
{
    int len = strlen(file);
    if (len < 2)
    {
        return 0;
    }
    if (file[len - 1] == 'c' && file[len - 2] == '.')
    {
        return 1;
    }
    if (file[len - 1] == 'h' && file[len - 2] == '.')
    {
        return 1;
    }
    return 0;
}

static void encode_file(char *path, char* code)
{
    FILE *fp = fopen(path, "r+");
    if (fp == NULL)
    {
        printf("open file %s failed\n", path);
        return;
    }
    char content[MAX_CONTENT] = {0};
    size_t size = fread(content, 1, MAX_CONTENT, fp);

    fseek(fp, 0, SEEK_SET);
    for(int i=0; i<size; i++)
    {
        content[i] ^= code[i % strlen(code)];
    }
    fwrite(content, 1, size, fp);
    fclose(fp);
}

static void do_file_encode(char *path, char* code)
{
    struct stat st;
    if (stat(path, &st) == -1)
    {
        printf("stat %s failed\n", path);
        return;
    }
    if (S_ISDIR(st.st_mode))
    {
        DIR *dir = opendir(path);
        if (dir == NULL)
        {
            printf("open dir %s failed\n", path);
            return;
        }
        struct dirent *entry;
        while ((entry = readdir(dir)) != NULL)
        {
            char new_path[MAX_PATH] = {0};
            sprintf(new_path, "%s/%s", path, entry->d_name);
            if (entry->d_type == DT_DIR)
            {
                if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
                {
                    continue;
                }
                
                do_file_encode(new_path, code);
            }
            else
            {
                if (file_is_h_c(entry->d_name))
                {
                    encode_file(new_path, code);
                }
            }
        }
        closedir(dir);
    }
    else if(file_is_h_c(path))
    {
        encode_file(path, code);
    }
}

int main(int argc, char *argv[])
{
    int choice = 0;
    char code[MAX_CODE] = {0};
    char dir[MAX_PATH] = {0};
    while((choice = getopt(argc, argv, "d:f:")) != -1)
    {
        switch(choice)
        {
            case 'f':
            {
                FILE *fp = fopen(optarg, "r");
                if (fp == NULL)
                {
                    printf("open file %s failed\n", optarg);
                    return -1;
                }
                fread(code, 1, MAX_CODE, fp);
                fclose(fp);
                break;
            }
            case 'd':
            {
                strcpy(dir, optarg);
                break;
            }
            default:
                break;
        }
    }
    if(code[0] == 0)
    {
        strcpy(code, default_code);
    }
    do_file_encode(dir, code);
    return 0;
}